<?php
/*
 * description：
 * author：wh
 * email：
 * createTime：{2023/11/22} {10:30} 
 */

namespace app\webautocode\controller;


use app\webautocode\extend\controller\BaseAdmin;
use think\App;
use think\Controller;
use think\Db;
use think\facade\Env;
use wanghua\general_utility_tools_php\http\Curl;
use wanghua\general_utility_tools_php\tool\Tools;

class Apimanage extends Controller
{
    //api接口文件保存地址
    private $api_code_root_path = '';
    //api接口文档地址
    private $api_doc_root_path = '';
    protected $controller_comments = '';//控制器注释
    public function __construct(App $app = null)
    {
        parent::__construct($app);
        //D:\wanghua\projects\mysql_web_sql_manage\application\webautocode\controller\Apimanage.php

        $code_save_path = input('code_save_path');
        if($code_save_path){
            //缓存代码存放路径
            cache('api_code_root_path',$code_save_path);//在页面显示
            if(substr($code_save_path,-1) != '\\'){
                $code_save_path .= '\\';
            }
            $this->api_code_root_path = $code_save_path.'application/api/controller/';
            $this->api_doc_root_path = $code_save_path.'public/apidoc/';

        }else{
            $path = str_replace('application\webautocode\controller','',__DIR__);
            $this->api_code_root_path = $path.'application/api/controller/';
            $this->api_doc_root_path = $path.'public/apidoc/';
        }
        $tablename = input('tablename');
        $this->controller_comments = $tablename?Tools::get_table_comments($tablename):'';

    }

    private function getTables(){
        $tab = Db::query('SELECT DATABASE() as name');
        return array_column(Db::query('SHOW TABLES;'), 'Tables_in_'.$tab[0]['name']);
    }
    /**
     * desc：设置api接口文件保存物理地址
     *
     * author：wh
     * @param string $path 项目根目录的物理路径，到application目录的上一级，注意：不是public根目录的意思
     *
     * 如：E:\wh\projects\mysql_web_sql_manage\
     *
     * 注意：参数必须以"/"结尾，否则会报错
     */
    function setApiCodeSavePath($path){
        $this->api_code_root_path = $path.'application/api/controller/';
    }

    //显示全部表
    function showtables(){

        $tab = Db::query('SELECT DATABASE() as name');

        //tp5.0和5.1区别大，要用config('app.database')获取数据库信息
        $tables = Db::query('SHOW TABLES;');//array_column(Db::query('SHOW TABLES;'), 'Tables_in_'.$tab[0]['name']);
        //dump($tables);die;
        foreach ($tables as &$table){
            $table['name'] = $table['Tables_in_'.$tab[0]['name']];
            $table['comments'] = Tools::get_table_comments($table['Tables_in_'.$tab[0]['name']]);
        }
        $this->assign('list', $tables);

        return $this->fetch();
    }


    /**
     * desc：查询提交过来的表名的字段
     *
     * author：wh
     */
    function showfields(){
        $this->assign('apiControllerName', str_replace('_','',ucfirst(str_replace('fa_','',input('tablename')))));

        $this->assign('api_code_root_path',cache('api_code_root_path')?:'');
        $this->assign('table_comments',Tools::get_table_comments(input('tablename')));

        $tablename = input('tablename');
        $this->assign('tablename',$tablename);

        $fields = Db::table($tablename)->getTableFields();
        $this->assign('field_list', $fields);

        $table_list = $this->getTables();
        $this->assign('table_list', $table_list);
        return $this->fetch();
    }

    /**
     * desc：构建api代码
     *
     * author：wh
     * @return \think\response\Json
     */
    function createapi()
    {

        //尝试写基类
        $this->createBaseController($this->api_code_root_path);
        //normal_api
        return $this->createNormalApi();
    }
    /**
     * desc：生成普通查询、关联查询接口
     *
     * 返回接口地址
     * author：wh
     */
    function createNormalApi(){


        //表
        $tablename = input('tablename');
        //根据表获取名称
        //$comments = Tools::get_comments_by_field($tablename)
        $condition_field = input('condition_field');//条件，多个字段逗号隔开
        //like查询
        $like_field = input('like_field');//like，多个字段逗号隔开

        $api_name = input('api_name');//接口名称
        $api_desc = input('api_desc');//接口说明

        $return_fields = input('return_fields');//返回，多个字段逗号隔开
        //为空则返回所有字段

        $return_data_num = input('return_data_num');//返回单条还是多条数据
        //接口域名
        $api_domain = input('api_domain');
        $is_must = input('is_must');//多个字段逗号隔开
        //时间范围查询
        $date_scope_field = input('date_scope_field');

        //返回数据值的字段名
        $rel_data_return_type_field_name = input('rel_data_return_type_field_name');
        //这里是为了判断
        $ret_field_name_arr = Tools::delete_str_empty_ele($rel_data_return_type_field_name);


        $rel_table = input('rel_table');

        $rel_data_return_type = input('rel_data_return_type');//关联字段返回类型,二维数组，一维数组，字段值

        //组装接口参数
        $api_param_str = $this->apiParamsRemark(input('like_field').','.input('condition_field'));
        $field_comments_str = $this->allFieldsRemark($tablename);
        $ret_field_name_str = '';
        if($ret_field_name_arr){
            $ret_field_name_str=<<<EOF
            \$ret_field_name_arr = Tools::delete_str_empty_ele('$rel_data_return_type_field_name');

            //处理为外键字段+外键对应数据的字段名 eg：users_id=>nickname
            \$ret_field_name2 = [];
            foreach (\$ret_field_name_arr as \$ret_typ_field) {
                \$exp_arr = explode('--',\$ret_typ_field);
                //\$exp_arr[0] 主表字段，\$exp_arr[1] 副表字段
                \$ret_field_name2[\$exp_arr[0]] = [\$exp_arr[0],\$exp_arr[1]];
            }
            
            //返回数据类型处理
            \$return_type_exp_arr = Tools::delete_str_empty_ele('$rel_data_return_type');
            //处理为类型+字段
            \$return_type_exp_arr2 = [];
            foreach (\$return_type_exp_arr as \$ret_type_field) {
                \$exp_arr = explode('==',\$ret_type_field);
                \$return_type_exp_arr2[\$exp_arr[0]] = \$exp_arr[1];
            }

            //返回数组 eg: [id-fa_goods_deal==goods_id,id-fa_goods_deal==goods_id]
            \$rel_table_arr = Tools::delete_str_empty_ele('$rel_table');
            //关联的字段和表
            \$rel_field_table_arr2 = [];
            //关系
            foreach (\$rel_table_arr as \$rel_str) {
                \$exp_arr = explode('-',\$rel_str);
                \$rel_field_table_arr2[\$exp_arr[0]] = [explode('==',\$exp_arr[1])[0],explode('==',\$exp_arr[1])[1]];
            }
EOF;

        }
        //获取条件参数
        $condition_str = "";
        if($condition_field){
            foreach (explode(',',$condition_field) as $cond_field){
                if(!in_array($cond_field, explode(',',$date_scope_field))){

                    $condition_str .= "
            \$$cond_field = input('$cond_field');";
                    //校验区
                    if($is_must && in_array($cond_field,explode(',',$is_must))){
                        $condition_str .= "
            if(empty(\$$cond_field)){
                return json(Tools::set_fail('参数错误'));
            }
                    ";
                    }
                }
            }
        }
        if($return_data_num == 'one' && empty(Tools::delete_str_empty_ele($condition_field))){
            return Tools::set_fail('查询单条数据时，必须指定一个查询条件');
        }
        //固定字段值
        $fix_field_val = input('fix_field_val');
        $get_data_str = "
            \$model_obj = Db::table(TabConf::\${$tablename});
        ";

        //固定值
        if($fix_field_val){
            $get_data_str .= $this->fix_field_val();
        }
        //like查询
        if($like_field){
            //like
            foreach (explode(',',$like_field)  as $like_field){

                $get_data_str.="
            if(input('$like_field')){
                \$model_obj->whereLike('$like_field','%'.input('$like_field').'%');
            }
            ";

            }
        }
        //普通where条件查询
        foreach (explode(',',$condition_field) as $field){
            //普通where条件
            if($field){
                if(!in_array($field, explode(',',$date_scope_field)) && !in_array($field, explode(',',$like_field))){
                    $get_data_str.="
            if(input('$field')){
                \$model_obj->where('$field',input('$field'));
            }";
                }
            }
        }
        //时间范围查询
        if ($date_scope_field){
            $get_data_str .= $this->date_scope_field();
        }
        //返回指定字段, 默认返回所有字段
        if($return_fields){
            //foreach ($return_fields as $return_field)
            $get_data_str.="
            \$model_obj->field('$return_fields');";
        }

        //分页
        $is_pagelist = input('is_pagelist');

        //返回单条还是多条
        if($return_data_num == 'one'){
            $get_data_str.=<<<EOF
            
            \$item = \$model_obj->find();
            
EOF;

            if($ret_field_name_arr){
                //查询关联数据代码
                $rel_query_str_no_pagelist = $this->pagelistcode();
                $get_data_str .= "
            
                {$ret_field_name_str}
                
                {$rel_query_str_no_pagelist}
                
            ";
            }
            $get_data_str .= "\$data = \$item;";
        }else{
            $rel_table = input('rel_table');
            //关联数据返回类型
            $each_rel_str = $this->pagelistcode();
            //分页
            if($is_pagelist == 'yes'){

                //关联表(字段名-表名)  id-fa_goods_deal==goods_id,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
                if($rel_table){

                    //默认返回二位数组

                    $get_data_str.="
        
            \$data = \$model_obj->paginate(['page'=>input('current_page',1),'list_rows'=>input('list_rows',15)])
            ->each(function(\$item, \$key){
               {$ret_field_name_str}
    
                $each_rel_str
                return \$item;
            });
            
            //  ['total'] => int(30)
            //  ['per_page'] => int(15)
            //  ['current_page'] => int(1)
            //  ['last_page''] => int(2)
            \$data = \$data->toArray();//包含 data列表
            ";
                }else{
                    $get_data_str.="
        
            \$data = \$model_obj->paginate(['page'=>input('current_page'),'list_rows'=>input('list_rows',15)]);
            
            //  ['total'] => int(30)
            //  ['per_page'] => int(15)
            //  ['current_page'] => int(1)
            //  ['last_page''] => int(2)
            \$data = \$data->toArray();//包含 data列表
            ";
                }
            }else{
                //不分页
                $get_data_str.="
            \$data = \$model_obj->select();
            if(empty(\$data)){
                return json(Tools::set_ok('ok',\$data));
            }
        
        ";
            }
        }
        $rel_query_str = '';
        //不分页时查询关联表的数据
        if($is_pagelist == 'no'){
            //查询关联数据代码
            $rel_query_str_no_pagelist = $this->pagelistcode();
            //有关联才有分页代码,这里判断返回类型即可
            if(!empty($ret_field_name_arr)){
                $rel_query_str = "
            
{$ret_field_name_str}
            foreach(\$data as &\$item){
                $rel_query_str_no_pagelist
            }
            ";
            }
        }

        $api_controller_name = input('api_controller_name')?:'Api';

        $api_func_str = <<<EOF
    /**
    * desc：{$api_desc}
    *
    * api/$api_controller_name/$api_name
    *
{$api_param_str}
    *
{$field_comments_str}
    * author：wh
    */
    function {$api_name}(){
        Tools::log_to_write_txt(['{$api_desc} 入参：'=>input()]);
        \$api_desc = '{$api_desc}';
        try {
            {$condition_str}
            
            {$get_data_str}
            
            {$rel_query_str}
            
            return json(Tools::set_ok('ok',\$data));
        }catch(\Exception \$e){
            Tools::log_to_write_txt([
                'error'=>'{$api_desc}.异常.'.\$e->getMessage(),
                '参数'=>input(),
                'error_info'=>\$e->getTraceAsString()
            ]);
            return json(Tools::set_res(500,'操作异常',[])); 
        }
    }
EOF;

        $api_controller = <<<EOF
<?php

namespace app\api\controller;

use think\Db;
use app\common\model\TabConf;
use wanghua\general_utility_tools_php\\file\upload\\FileUpload;
use wanghua\general_utility_tools_php\\tool\Tools;
use wanghua\general_utility_tools_php\Validate;
use think\Controller;

class {$api_controller_name} extends BaseHttpApi
{
    protected \$controller_comments = '{$this->controller_comments}';
    
$api_func_str
    
}
EOF;


        $file_path = $this->api_code_root_path;
        if(!file_exists($file_path)){
            mkdir($file_path,0777,true);
        }
        $file_path.=$api_controller_name.'.php';
        //验证同名接口
        $api_func_name_check = $this->api_func_name_check($file_path,$api_name);
        if($api_func_name_check['code'] != 200){
            return json($api_func_name_check);
        }

        if(!file_exists($file_path)){
            file_put_contents($file_path,$api_controller,FILE_APPEND);
        }else{
            //存在，追加
            $old_code_str = file_get_contents($file_path);
            $old_code_str = substr($old_code_str,0,strlen($old_code_str)-2);
            $new_code_str=$old_code_str.$api_func_str.'
}';
            file_put_contents($file_path,$new_code_str);
        }




        $api_url = "/api/$api_controller_name/$api_name";

        //生成文档
        $this->createApiJsonDoc($api_domain,$api_url);


        return json(Tools::set_ok('ok',['api_url'=>$api_url]));
    }

    /**
     * desc：分页的关联查询代码
     * author：wh
     * @return string
     */
    private function pagelistcode(){
        //返回数据值的字段名
        $rel_data_return_type_field_name = input('rel_data_return_type_field_name');
        //这里是为了判断
        $ret_field_name_arr = Tools::delete_str_empty_ele($rel_data_return_type_field_name);

        if(empty($ret_field_name_arr)){
            return '';
        }
        $str = <<<EOF

            foreach(\$item as \$it_key=>\$it_val){
                if(empty(\$rel_field_table_arr2[\$it_key])){
                    continue;
                }
                foreach(\$return_type_exp_arr as \$key=>\$val){
                    \$val_arr = explode('==',\$val);
                    if(\$it_key == \$val_arr[0]){
                        switch(\$val_arr[1]){
                            case 'two_arr':
                            \$item[\$it_key.'_data'] = Db::table(\$rel_field_table_arr2[\$it_key][0])->where("{\$rel_field_table_arr2[\$it_key][1]}",\$it_val)->select();
                                break;
                            case 'one_arr':
                            \$item[\$it_key.'_data'] = Db::table(\$rel_field_table_arr2[\$it_key][0])->where("{\$rel_field_table_arr2[\$it_key][1]}",\$it_val)->find();
                                break;
                            case 'field_val':
                            \$item[\$it_key.'_data'] = Db::table(\$rel_field_table_arr2[\$it_key][0])->where("{\$rel_field_table_arr2[\$it_key][1]}",\$it_val)->value("{\$ret_field_name2[\$it_key][1]}");
                                break;
                        }
                    }
                }
            }
EOF;

        return $str;
    }
    /**
     * desc：创建基类
     * author：wh
     */
    protected function createBaseController($path){
        $file_name = $path.'\BaseHttpApi.php';
        if(file_exists($file_name)){
            //禁止重复写
            return false;
        }
        if(!file_exists($path)){
            mkdir($path,0777,true);
        }

        $base_ctl_str = <<<EOF
<?php
/*
 * description：
 * author：wh
 * email：
 */

namespace app\api\controller;


use think\Db;
use app\common\model\TabConf;
use wanghua\general_utility_tools_php\\framework\base\BaseAuthController;
use think\\facade\Request;
use wanghua\general_utility_tools_php\\file\upload\\FileUpload;
use wanghua\general_utility_tools_php\\tool\\Tools;

class BaseHttpApi extends BaseAuthController
{
    //控制器注释
    protected \$controller_comments = '';


    
    
    
}
EOF;
        return file_put_contents($file_name,$base_ctl_str);
    }


    /**
     * desc：固定字段值
     * author：wh
     */
    private function fix_field_val(){
        $fix_field_val = input('fix_field_val');

        //先处理逗号隔开
        $arr = Tools::delete_str_empty_ele($fix_field_val);

        $code_str = '';
        foreach ($arr as $ket_val){
            $exp_arr = explode('--',$ket_val);//0下标为字段名，1下标为输入的值
            $code_str .= "
        \$model_obj->where('{$exp_arr[0]}','{$exp_arr[1]}');
            ";
        }
        return $code_str;
    }
    /**
     * desc：时间范围查询
     *
     * 参数前 需要用前缀 start_ 和 end_
     *
     * author：wh
     */
    private function date_scope_field(){
        $date_scope_field = input('date_scope_field');
        $arr = explode(',',$date_scope_field);

        $code_str = '';
        foreach ($arr as $date_field){
            //开始时间字段
            $start_time_field = 'start_'.$date_field;
            //结束时间字段
            $end_time_field = 'end_'.$date_field;


            if($start_time_field){
                $code_str .= "
        if(input('{$start_time_field}')){
            \$model_obj->where('{$date_field}','egt', input('{$start_time_field}'));
        }
            ";
            }
            if($end_time_field){
                $code_str .= "
        if(input('{$end_time_field}')){
            \$model_obj->where('{$date_field}','elt', input('{$end_time_field}'));
        }
            ";
            }
        }
        return $code_str;
    }
    /**
     * desc：生成文档
     *
     * author：wh
     */
    private function createApiJsonDoc($api_domain,$api_url){
        $condition_field = input('condition_field');//条件，多个字段逗号隔开
        //$api_name = input('api_name');//接口名称
        $api_desc = input('api_desc');
        $tablename = input('tablename');

        $params = [];
        //时间范围
        $date_scope_field = input('date_scope_field');
        $is_must = input('is_must');
        $exp_must = explode(',',$is_must);
        //一般条件
        if($condition_field){
            foreach (explode(',',$condition_field) as $cond_field){
                if(!in_array($cond_field, explode(',',$date_scope_field))){
                    $params[$cond_field] = in_array($cond_field,$exp_must)?$this->getCommentsByField($tablename,$cond_field).' 必须':'';
                }
            }
        }

        //分页
        $is_pagelist = input('is_pagelist');
        if($is_pagelist == 'yes'){
            $params['current_page'] = '当前页码，必须';
            $params['list_rows'] = '每页条数，必须';
        }

        if($date_scope_field){
            $arr = explode(',',$date_scope_field);
            foreach ($arr as $field){
                $params['start_'.$field] = in_array($field,$exp_must)?$this->getCommentsByField($tablename,$field).' 必须':'';
                $params['end_'.$field] = in_array($field,$exp_must)?$this->getCommentsByField($tablename,$field).' 必须':'';
            }
        }


        //固定参数 ,,,,,,,,,,status--200,,,,,,,,
        $fix_field_val = input('fix_field_val');
        if($fix_field_val){
            //先处理逗号隔开
            $arr = Tools::delete_str_empty_ele($fix_field_val);
            foreach ($arr as $key_val_str){
                $key_val_exp = explode('--',$key_val_str);
                // 添加到文档生成参数 start
                $params[$key_val_exp[0]] = $key_val_exp[1].$this->getCommentsByField($tablename,$key_val_exp[0]).'【固定参数】';
                // 添加到文档生成参数 end
            }
        }

        $params = $this->getFieldComments($params,$tablename);
        $json_param = json_encode($params,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE);
        $json_md_doc = <<<EOF
## 接口说明
```` 
    $api_desc 
````

### api请求域名
```` 
    $api_domain 
````

### 请求url地址
```` 
    $api_url 
````

### 请求参数
```` 
$json_param
````

### 响应结果
```` 
注意：为了便于开发功能，返回的json中，第一级有一维数组和二维数组之分，第二级开始，都是返回二维数组
 
````



EOF;

        //$this->writeDocText($json_md_doc);

    }

    /**
     * desc：循环获取字段的注释
     *
     * author：wh
     */
    private function getFieldComments(array $params, $table){

        $arr = [];
        foreach ($params as $key=>$val){
            $comts = Tools::get_comment_By_Field($table,$key);
            $arr[$key] = $val .'（'.$comts.'）';
        }

        return $arr;
    }

    /**
     * @deprecated
     *
     * desc：查询关联表中的数据
     *
     * author：wh
     */
    private function get_rel_table_data($each_rel_str){

        //关联表(字段名-表名)  id-fa_goods_deal==goods_id,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
        $rel_table = input('rel_table');
        //主表字段
        if(empty($rel_table)){
            return '';
        }


        //生成查询代码，无论结果是一条数据还是多条，返回的结构都是二维数组
        $rel_query_str = <<<EOF

        //返回数组 eg: [id-fa_goods_deal==goods_id,id-fa_goods_deal==goods_id]
        \$rel_table_arr = Tools::delete_str_empty_ele('$rel_table');
        //关联的字段和表
        \$rel_field_table_arr2 = [];
        if(\$rel_table_arr){
            foreach (\$rel_table_arr as \$rel_str) {
                \$exp_arr = explode('-',\$rel_str);
                \$rel_field_table_arr2[\$exp_arr[0]] = [explode('==',\$exp_arr[1])[0],explode('==',\$exp_arr[1])[1]];
            }
        }
        
        
        
        //\$data 此变量有一维数组和二维数组之分
        //这里修改的data引用, 后续使用data同名变量时要unset掉
        if(empty(\$data)) return json(Tools::set_fail('未查询到数据'));
        foreach(\$data as \$key => &\$item){
            //区分数组维度
            if(is_array(\$item)){
                //为空直接跳过
                if(empty(\$rel_field_table_arr2)) continue;
                //二维数组          关联键 eg:id       关联键的值 eg:89
                //\$item是键值对关系
                foreach( \$item as \$tow_key => \$tow_val){
                    if(!empty(\$rel_field_table_arr2[\$tow_key])){
                        \$rel_obj = Db::table(TabConf::\$\$rel_field_table_arr2[\$tow_key][0]);
                        \$rel_obj->where("{\$rel_field_table_arr2[\$tow_key][1]}",\$tow_val);
                        //键+"_data"格式作为数据的键
                        \$item[str_replace('fa_','',\$rel_field_table_arr2[\$tow_key][0]).'_data'] = \$rel_obj->select();//始终返回二维数组
                    }
                    //不存在则跳过
                }
            }else{
                if(empty(\$rel_field_table_arr2[\$key])) continue;
                //一维数组 \$key是键  \$item是值
                \$rel_obj = Db::table(TabConf::$\$rel_field_table_arr2[\$key][0]);
                \$rel_obj->where("{\$rel_field_table_arr2[\$key][1]}",\$item);
                //键+"_data"格式作为数据的键
                \$data[str_replace('fa_','',\$rel_field_table_arr2[\$key][0]).'_data'] = \$rel_obj->select();//始终返回二维数组
            }
        }
        
EOF;
        return $rel_query_str;
    }
    /**
     * @deprecated
     *
     * desc：分页查询关联表中的数据
     *
     * author：wh
     */
    private function get_rel_table_data_pagelist(){

        //关联表(字段名-表名)  id-fa_goods_deal==goods_id,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
        $rel_table = input('rel_table');
        //主表字段
        if(empty($rel_table)){
            return '';
        }


        //生成查询代码，无论结果是一条数据还是多条，返回的结构都是二维数组
        $rel_query_str = <<<EOF

      
        
EOF;
        return $rel_query_str;
    }


    /**
     * desc：验证同名接口
     * author：wh
     * @param $file_path
     * @param $api_name
     * @return array
     */
    private function api_func_name_check($file_path,$api_name){
        if(!file_exists($file_path)){
            return Tools::set_ok();
        }
        $old_str = file_get_contents($file_path);
        return strpos($old_str,$api_name)?Tools::set_fail('已存在同名方法'):Tools::set_ok();
    }

    /**
     * desc：添加到文档参数
     *
     * author：wh
     * @param $params
     * @param $field_arr_str
     * @return bool
     */
    private function addToDocParams(&$params, $field_arr_str=[])
    {
        if(empty($field_arr_str)){
            return false;
        }
        //is_must: create_time,update_time
        $is_must = input('is_must');
        if(empty($is_must)){
            if(is_array($field_arr_str)){
                foreach ($field_arr_str as $field){
                    $params[$field] = '';
                }
            }
            if(is_string($field_arr_str)){
                $params[$field_arr_str] = '';
            }
        }else{
            $exp_must = explode(',',$is_must);
            if(is_array($field_arr_str)){
                foreach ($field_arr_str as $field){

                    $params[$field] = in_array($field,$exp_must)?'必须':'';
                }
            }
            if(is_string($field_arr_str)){
                $params[$field_arr_str] = in_array($field_arr_str,$exp_must)?'必须':'';
            }
        }
        return true;
    }

    /**
     * desc：获取关联表的字段并以option格式返回
     *
     * author：wh
     * @return array
     */
    function reltablefieldsoptionhtml(){
        $rel_table_name = input('rel_table_name');
        $fields = Db::table($rel_table_name)->getTableFields();
        $this->assign('fields',$fields);
        $html = $this->fetch()->getContent();

        return Tools::set_ok('ok',$html);
    }


    /**
     * @deprecated 废弃，使用框架类的/index/test/buildApiDoc方法构建，可一键测试接口
     *
     * desc：
     * author：wh
     * @param $json_md_doc
     */
    private function writeDocText($json_md_doc){

        $api_controller_name = input('api_controller_name')?:'Api';
        $api_name = input('api_name');

        $path = $this->api_doc_root_path.$this->controller_comments.'-'.$api_controller_name;
        if(!file_exists($path)){
            mkdir($path,0777,true);
        }
        $api_desc = input('api_desc');//接口说明
        $api_name = strtolower($api_name);//要转为小写，兼容tp框架
        file_put_contents($path."/{$api_desc}-{$api_name}.MD", $json_md_doc);
    }


    /**
     * desc：生成新增API界面
     *
     * author：wh
     * @return mixed
     */
    function showfieldstoadd(){
        $this->assign('apiControllerName', str_replace('_','',ucfirst(str_replace('fa_','',input('tablename')))));

        $this->assign('api_code_root_path',cache('api_code_root_path')?:'');
        $this->assign('table_comments',Tools::get_table_comments(input('tablename')));

        $tablename = input('tablename');
        $this->assign('tablename',$tablename);

        $fields = Db::table($tablename)->getTableFields();
        $this->assign('field_list', $fields);

        $table_list = $this->getTables();
        $this->assign('table_list', $table_list);
        return $this->fetch();
    }

    /**
     * desc：生成单表新增api
     * author：wh
     */
    function createaddapi(){
        //尝试写基类
        $this->createBaseController($this->api_code_root_path);

        $field = input('input_fields');
        $tablename = input('tablename');

        $api_name = input('api_name');//接口名称
        $api_desc = input('api_desc');

        $is_must = input('is_must');

        $api_domain = input('api_domain');
        $api_controller_name = input('api_controller_name')?:'Api';
        $arr = Tools::delete_str_empty_ele($field);


        //获取参数
        $condition_str = "";
        if($field){
            foreach (explode(',',$field) as $k => $cond_field){
                $condition_str .= "
            \$$cond_field = input('$cond_field');";
                //校验区
                if($is_must && in_array($cond_field,explode(',',$is_must))){
                    $condition_str .= "
            if(empty(\$$cond_field)){
                return json(Tools::set_fail('参数错误.$k'));
            }
                    ";
                }
            }
        }
        //组装接口参数
        $api_param_str = $this->apiParamsRemark(input('input_fields'));

        $func_str = <<<EOF
    
    /**
    * $api_desc
    *
{$api_param_str}
    * api/$api_controller_name/$api_name
    */
    function $api_name(){
        Tools::log_to_write_txt(['{$api_desc}'=>input()]);
        \$api_desc = '{$api_desc}';
        Db::startTrans();
        try {
            $condition_str

EOF;


        $code_str = '
            $data = [';
        foreach ($arr as $field){
            $code_str .= <<<EOF
        
                '$field'=>\${$field}?:'',
EOF;
        }
        $code_str .= "
            ];";
        //文件上传字段
        $file_upload_field = input('file_upload_field');
        if($file_upload_field){
            foreach (explode(',',$file_upload_field) as $fl_field){
                if($is_must && in_array($fl_field,explode(',',$is_must))){
                    $code_str .= <<<EOF
            
            //文件上传(图片、文件等)
            \$res = (new FileUpload())->files('{$fl_field}_upload');//指定上传控件name，多文件则需要在name后面加[]
            if(\$res['code'] > 0){
                return json(Tools::set_fail('上传失败.'.\$res['msg']));
            }
            //多个用逗号隔开
            \$data['$fl_field'] = implode(',',array_column(\$res['data'],'outer_req_relative_url'));
EOF;

                }else{
                    $code_str .= <<<EOF
            
            //文件上传(图片、文件等)
            \$res = (new FileUpload())->files('{$fl_field}_upload');//指定上传控件name，多文件则需要在name后面加[]
            if(\$res['code'] == 0){
                //多个用逗号隔开
                \$data['$fl_field'] = implode(',',array_column(\$res['data'],'outer_req_relative_url'));
            }
EOF;
                }
            }
        }

        $code_str .= "   
          
        
            \$dataid = Db::table(TabConf::\${$tablename})->insertGetId(\$data);
        
            \$this->operateLog('$api_desc',api_user_info('id'));
            Db::commit();
            return json(Tools::set_ok('ok',\$dataid));
        }catch (\Exception \$e){
            Db::rollback();
            Tools::log_to_write_txt([
                'error'=>'{$api_desc}.异常.'.\$e->getMessage(),
                'input'=>input(),
                'error_info'=>\$e->getTraceAsString()
            ]);
            return json(Tools::set_fail());
        }
    }
";
        //追加方法
        $api_func_str = $func_str.$code_str;


        $api_controller = <<<EOF
<?php

namespace app\api\controller;

use think\Db;
use app\common\model\TabConf;
use wanghua\general_utility_tools_php\\file\upload\\FileUpload;
use wanghua\general_utility_tools_php\\tool\Tools;
use think\Controller;

class {$api_controller_name} extends BaseHttpApi
{
    protected \$controller_comments = '{$this->controller_comments}';
    
    $api_func_str
    
}
EOF;
        $file_path = $this->api_code_root_path;
        if(!file_exists($file_path)){
            mkdir($file_path,0777,true);
        }
        $file_path.=$api_controller_name.'.php';
        //验证同名接口
        $api_func_name_check = $this->api_func_name_check($file_path,$api_name);
        if($api_func_name_check['code'] != 200){
            return json($api_func_name_check);
        }

        if(!file_exists($file_path)){
            file_put_contents($file_path,$api_controller,FILE_APPEND);
        }else{
            //存在，追加
            $old_code_str = file_get_contents($file_path);
            $old_code_str = substr($old_code_str,0,strlen($old_code_str)-2);
            $new_code_str=$old_code_str.$api_func_str.'
}';
            file_put_contents($file_path,$new_code_str);
        }



        //生成文档
        $api_url = "/api/$api_controller_name/$api_name";
        $params = [];
        foreach ($arr as $field){
            $params[$field] = '';
        }

        //文件上传字段，多个字段逗号隔开
        $file_upload_field = explode(',',input('file_upload_field'));
        if($file_upload_field){
            foreach ($file_upload_field as $field){
                $params[$field.'_upload'] = '文件上传字段name[]';
            }
        }
        $params = $this->getFieldComments($params,$tablename);

        $json_param = json_encode($params,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE);
        $json_md_doc = <<<EOF
## 接口说明
```` 
$api_desc 
````

### api请求域名
```` 
$api_domain 
````

### 请求url地址
```` 
$api_url 
````

### 请求参数
```` 
$json_param
````

### 响应结果
```` 
    注意：为了便于开发功能，请参考api返回的json数据
    
````

````
{
    code:200,//500失败、错误
    msg:'提示',
    data:[
        //......
    ],
}
````

EOF;

        //$this->writeDocText($json_md_doc);

        return Tools::set_ok('ok',['api_url'=>$api_url]);
    }


    /**
     * desc：生成修改API界面
     * author：wh
     */
    function showfieldstoupdate(){
        $this->assign('apiControllerName', str_replace('_','',ucfirst(str_replace('fa_','',input('tablename')))));

        $this->assign('api_code_root_path',cache('api_code_root_path')?:'');
        $this->assign('table_comments',Tools::get_table_comments(input('tablename')));

        $tablename = input('tablename');
        $this->assign('tablename',$tablename);

        $fields = Db::table($tablename)->getTableFields();
        $this->assign('field_list', $fields);

        $table_list = $this->getTables();
        $this->assign('table_list', $table_list);
        return $this->fetch();
    }
    /**
     * desc：生成单表修改api
     * author：wh
     */
    function createupdateapi(){
        //尝试写基类
        $this->createBaseController($this->api_code_root_path);

        $field = input('input_fields');
        $tablename = input('tablename');

        $api_name = input('api_name');//接口名称
        $api_desc = input('api_desc');

        $is_must = input('is_must');

        $api_domain = input('api_domain');
        $api_controller_name = input('api_controller_name')?:'Api';
        $arr = Tools::delete_str_empty_ele($field);

        $condition_field = input('condition_field');//修改条件
        $condition_field = Tools::delete_str_empty_ele($condition_field);
        //dump($condition_field);die;
        $update_condition_str = '';//修改条件代码块
        if($condition_field){
            //$update_condition_str.="\n";//增加一个换行
            foreach ($condition_field as $cf_key=>$val){
                $update_condition_str.=<<<EOF
                ->where('$val',input('$val'))
EOF;
                if($cf_key < count($condition_field)-1){//最后一个不增加换行
                    $update_condition_str.="\n";//增加一个换行
                }
            }
        }

        //获取参数
        $condition_str = "";
        if($field){
            foreach (explode(',',$field) as $k => $cond_field){
                $condition_str .= "
            \$$cond_field = input('$cond_field');";
                //校验区
                if($is_must && in_array($cond_field,explode(',',$is_must))){
                    $condition_str .= "
            if(empty(\$$cond_field)){
                return json(Tools::set_fail('参数错误.$k'));
            }
                    ";
                }
            }
        }
        if($condition_field){
            //校验修改条件字段
            foreach ($condition_field as $k => $cond_field){
                $condition_str .= "";
                //校验区
                    $condition_str .= "
            if(empty(input('$cond_field'))){
                return json(Tools::set_fail('参数错误。$k'));
            }
                    ";
            }
        }

        //组装接口参数
        $api_param_str = $this->apiParamsRemark(input('condition_field').','.input('input_fields'));
        $func_str = <<<EOF

   /**
    * $api_desc
{$api_param_str}
    * api/$api_controller_name/$api_name
    */
    function $api_name(){
        Tools::log_to_write_txt(['{$api_desc}'=>input()]);
        
        \$api_desc = '{$api_desc}';
        Db::startTrans();
        try {
            $condition_str

EOF;


        $code_str = '
            $data = [';
        foreach ($arr as $field){
            $code_str .= <<<EOF
        
                '$field'=>\${$field}?:'',
EOF;
        }

        $code_str .= "
            ];";
        //文件上传字段
        $file_upload_field = input('file_upload_field');
        if($file_upload_field){
            foreach (explode(',',$file_upload_field) as $fl_field){
                if($is_must && in_array($fl_field,explode(',',$is_must))){
                    $code_str .= <<<EOF
            
            //文件上传(图片、文件等)
            \$res = (new FileUpload())->files('{$fl_field}_upload');//指定上传控件name，多文件则需要在name后面加[]
            if(\$res['code'] > 0){
                return json(Tools::set_fail('上传失败.'.\$res['msg']));
            }
            //多个用逗号隔开
            \$data['$fl_field'] = implode(',',array_column(\$res['data'],'outer_req_relative_url'));
EOF;

                }else{
                    $code_str .= <<<EOF
            
            //文件上传(图片、文件等)
            \$res = (new FileUpload())->files('{$fl_field}_upload');//指定上传控件name，多文件则需要在name后面加[]
            if(\$res['code'] == 0){
                //多个用逗号隔开
                \$data['$fl_field'] = implode(',',array_column(\$res['data'],'outer_req_relative_url'));
            }
EOF;
                }
            }
        }
        $code_str .= "   
        
        
            \$dataid = Db::table(TabConf::\${$tablename})
                ->data(\$data)
$update_condition_str
                ->update();
        
            \$this->operateLog('$api_desc',api_user_info('id'));
            Db::commit();
            return json(Tools::set_ok('ok',\$dataid));
        }catch (\Exception \$e){
            Db::rollback();
            Tools::log_to_write_txt([
                'error'=>'{$api_desc}.异常.'.\$e->getMessage(),
                'input'=>input(),
                'error_info'=>\$e->getTraceAsString()
            ]);
            return json(Tools::set_fail());
        }
    }
";
        //追加方法
        $api_func_str = $func_str.$code_str;


        $api_controller = <<<EOF
<?php

namespace app\api\controller;

use think\Db;
use app\common\model\TabConf;
use wanghua\general_utility_tools_php\\file\upload\\FileUpload;
use wanghua\general_utility_tools_php\\tool\Tools;
use think\Controller;

class {$api_controller_name} extends BaseHttpApi
{
    protected \$controller_comments = '{$this->controller_comments}';
    
$api_func_str
    
}
EOF;
        $file_path = $this->api_code_root_path;
        if(!file_exists($file_path)){
            mkdir($file_path,0777,true);
        }
        $file_path.=$api_controller_name.'.php';
        //验证同名接口
        $api_func_name_check = $this->api_func_name_check($file_path,$api_name);
        if($api_func_name_check['code'] != 200){
            return json($api_func_name_check);
        }

        if(!file_exists($file_path)){
            file_put_contents($file_path,$api_controller,FILE_APPEND);
        }else{
            //存在，追加
            $old_code_str = file_get_contents($file_path);
            $old_code_str = substr($old_code_str,0,strlen($old_code_str)-2);
            $new_code_str=$old_code_str.$api_func_str.'
}';
            file_put_contents($file_path,$new_code_str);
        }



        //生成文档
        $api_url = "/api/$api_controller_name/$api_name";
        $params = [];
        foreach ($arr as $field){
            $params[$field] = '';
        }

        //必须的条件参数
        foreach ($condition_field as $str){
            $params[$str] = '必须的条件参数';
        }

        //文件上传字段，多个字段逗号隔开
        $file_upload_field = explode(',',input('file_upload_field'));
        if($file_upload_field){
            foreach ($file_upload_field as $field){

                $params[$field.'_upload'] = '文件上传字段name[]';
            }
        }
        $params = $this->getFieldComments($params,$tablename);
        $json_param = json_encode($params,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE);
        $json_md_doc = <<<EOF
## 接口说明
```` 
$api_desc 
````

### api请求域名
```` 
$api_domain 
````

### 请求url地址
```` 
$api_url 
````

### 请求参数
```` 
$json_param
````


### 响应结果
```` 
    注意：为了便于开发功能，请参考api返回的json数据
````

````
{
    code:200,//500失败、错误
    msg:'提示',
    data:[
        //......
    ],
}
````

EOF;

        //$this->writeDocText($json_md_doc);

        return Tools::set_ok('ok',['api_url'=>$api_url]);
    }

    /**
     * desc：生成求和api，支持多字段求和、分组单字段、多字段求和
     * author：wh
     * @return mixed
     */
    function showfieldstosum(){
        $this->assign('apiControllerName', str_replace('_','',ucfirst(str_replace('fa_','',input('tablename')))));

        $this->assign('api_code_root_path',cache('api_code_root_path')?:'');
        $this->assign('table_comments',Tools::get_table_comments(input('tablename')));

        $tablename = input('tablename');
        $this->assign('tablename',$tablename);

        $fields = Db::table($tablename)->getTableFields();
        $this->assign('field_list', $fields);

        $table_list = $this->getTables();
        $this->assign('table_list', $table_list);
        return $this->fetch();
    }

    /**
     * desc：生成求和api
     * author：wh
     */
    function createsumapi(){
        //尝试写基类
        $this->createBaseController($this->api_code_root_path);

        //$field = input('input_fields');
        $tablename = input('tablename');

        $api_name = input('api_name');//接口名称
        $api_desc = input('api_desc');

        $is_must = input('is_must');

        $api_domain = input('api_domain');
        $api_controller_name = input('api_controller_name')?:'Api';
        //$arr = Tools::delete_str_empty_ele($field);
        $like_field = input('like_field');//like条件字段
        $like_field = Tools::delete_str_empty_ele($like_field);

        $condition_field = input('condition_field');//修改条件
        $condition_field = Tools::delete_str_empty_ele($condition_field);
        //求和字段
        $choose_aggr_func = input('choose_aggr_func');
        $choose_aggr_func = Tools::delete_str_empty_ele($choose_aggr_func);
        //时间范围
        $date_scope_field = input('date_scope_field');
        $date_scope_field = Tools::delete_str_empty_ele($date_scope_field);



        $condition_str = <<<EOF
    \$obj = Db::table(TabConf::\${$tablename});
EOF;
        //修改条件代码
        if($condition_field){
            foreach ($condition_field as $field){
                if($like_field&&in_array($field,$like_field)){
                    $condition_str .= "
                if(input('$field')){
                    \$obj->whereLike('$field','%'.input('$field').'%');
                }
                ";
                }
                //时间范围
                elseif($date_scope_field && in_array($field,$date_scope_field)){
                    $condition_str .= "
                if(input('$field')){
                    \$obj->where('$field','egt',input('start_{$field}'));
                    \$obj->where('$field','elt',input('end_{$field}'));
                }
                ";

                }else{
                    $condition_str .= "
                
                \$obj->where('$field',input('$field'));
                ";
                }
            }

        }

        if($choose_aggr_func){
            //支持常用聚合
            foreach ($choose_aggr_func as $field){
                $exp = explode('--',$field);
                $condition_str .= "
                \$obj->field('{$exp[1]}({$exp[0]}) as {$exp[1]}_{$exp[0]}');
                ";
            }
        }
        //固定值
        $fix_field_val = input('fix_field_val');
        $fix_field_val = Tools::delete_str_empty_ele($fix_field_val);
        if($fix_field_val){
            foreach ($fix_field_val as $field){
                $exp_f = explode('--',$field);
                $condition_str .= "
                \$obj->where('{$exp_f[0]}','{$exp_f[1]}');
                ";
            }
        }
        //分组字段，仅支持一个分组字段，复杂分组请手写代码，(分组字段必须在select字段中存在)
        $group_by_field = input('group_by_field');
        if($group_by_field){

            $condition_str .= "
            \$obj->group('$group_by_field');
            \$data = \$obj->select();";

        }else{

            //可能会有多个sum函数,只能用find
            $condition_str .= "
            \$data = \$obj->find();";

        }




        $api_func_str = <<<EOF
/**
     * desc：{$api_desc}
     * author：wh
     * 
     * api/$api_controller_name/$api_name
     */
    function {$api_name}(){
        Tools::log_to_write_txt(['{$api_desc} 入参：'=>input()]);
        \$api_desc = '{$api_desc}';
        try {
            {$condition_str}
            
            return json(Tools::set_ok('ok',\$data));
        }catch(\Exception \$e){
           Tools::log_to_write_txt([
                'error'=>'{$api_desc}.异常.'.\$e->getMessage(),
                '参数'=>input(),
                'error_info'=>\$e->getTraceAsString()
            ]);
            return json(Tools::set_res(500,'操作异常',[])); 
        }
    }
EOF;

        $api_controller = <<<EOF
<?php

namespace app\api\controller;

use think\Db;
use app\common\model\TabConf;
use wanghua\general_utility_tools_php\\file\upload\\FileUpload;
use wanghua\general_utility_tools_php\\tool\Tools;
use think\Controller;

class {$api_controller_name} extends BaseHttpApi
{
    protected \$controller_comments = '{$this->controller_comments}';

    $api_func_str
    
}
EOF;


        $file_path = $this->api_code_root_path;
        if(!file_exists($file_path)){
            mkdir($file_path,0777,true);
        }
        $file_path.=$api_controller_name.'.php';
        //验证同名接口
        $api_func_name_check = $this->api_func_name_check($file_path,$api_name);
        if($api_func_name_check['code'] != 200){
            return json($api_func_name_check);
        }

        if(!file_exists($file_path)){
            file_put_contents($file_path,$api_controller,FILE_APPEND);
        }else{
            //存在，追加
            $old_code_str = file_get_contents($file_path);
            $old_code_str = substr($old_code_str,0,strlen($old_code_str)-2);
            $new_code_str=$old_code_str.$api_func_str.'
}';
            file_put_contents($file_path,$new_code_str);
        }


        $api_url = "/api/$api_controller_name/$api_name";

        //生成文档
        $this->createApiJsonDoc($api_domain,$api_url);


        return json(Tools::set_ok('ok',['api_url'=>$api_url]));
    }

    /**
     * desc：获取字段注释
     * author：wh
     * @param $tablename
     * @param $field
     * @return mixed
     */
    private function getCommentsByField($tablename,$field){
        $field_comments = Tools::get_comments_by_field($tablename);
        $arr = Tools::key_val_arr($field_comments,'column_name','column_comment');
        return $arr[$field];
    }


    /**
     * desc：接口参数说明
     * author：wh
     */
    private function apiParamsRemark($condition_field){
        //$condition_field = input('condition_field');
        $tablename = input('tablename');//表名
        $exp = explode(',',$condition_field);//查询条件
        $is_pagelist = input('is_pagelist');//是否分页
        $api_param_str = <<<EOF
    * 参数：
EOF;
        $api_param_str .= "\n";//追加一个换行
        if($is_pagelist && $is_pagelist != 'no'){
            $api_param_str.=<<<EOF
    * 带分页
    * current_page 当前页码
    * list_rows 每页显示条数 默认15
EOF;

            $api_param_str .= "\n";//追加一个换行
        }
        foreach ($exp as $ep_key =>$field){
            if(empty($field)){
                continue;
            }
            //查询字段名注释
            $field_comments = $this->getCommentsByField($tablename,$field);
            $api_param_str .= <<<EOF
    * $field $field_comments
EOF;
            if($ep_key != count($exp)-1){
                $api_param_str .= "\n";//追加一个换行
            }
        }



        return $api_param_str;
    }
    /**
     * desc：所有字段说明
     * author：wh
     */
    private function allFieldsRemark($condition_field){
        //$condition_field = input('condition_field');
        $tablename = input('tablename');//表名
        $exp = explode(',',$condition_field);//查询条件
        $api_param_str = <<<EOF
    * 所有字段说明<span style="color: gray">（可能有部分额外字段未在此体现）</span>：
EOF;
        //查询表所有字段
        $field_comments = Tools::get_comments_by_field($tablename);
        $api_param_str .= "\n";//追加一个换行
        foreach ($field_comments as $ep_key =>$field){//$column_name =>$column_comment
            //if(empty($field)){
            //    continue;
            //}
            if($ep_key == 0){
                $api_param_str.="    ";
            }
            $column_name = $field['column_name'];
            $column_comment = $field['column_comment'];
            $api_param_str .= <<<EOF
* $column_name $column_comment
    
EOF;
            //if($ep_key != count($exp)-1){
            //    $api_param_str .= "\n";//追加一个换行
            //}
        }



        return $api_param_str;
    }

    /**
     * desc：接口测试html
     *
     * author：wh
     */
    function testapi(){
        //表
        $tablename = input('tablename');
        $condition_field = input('condition_field');//条件，多个字段逗号隔开
        $api_controller_name = input('api_controller_name')?:'Api';
        //域名
        $api_domain = input('api_domain');

        $api_name = input('api_name');//接口名称
        //接口地址
        $api_url = $api_domain."/api/$api_controller_name/$api_name";
        $this->assign('api_url',$api_url);

        $api_desc = input('api_desc');//接口说明
        $this->assign('api_desc',$api_desc);

        $condition_field_arr = Tools::delete_str_empty_ele($condition_field);

        $field_arr = [];
        if($condition_field_arr){

            foreach ($condition_field_arr as $field){

                $data_type_arr = Tools::get_data_type_by_field($tablename);
                $data_type = empty($data_type_arr[$field])?'':$data_type_arr[$field];
                $data = [
                    'field'=>$field,
                    'msg'=>Tools::get_comment_By_Field($tablename,$field),
                ];
                if(false !== strpos($data_type,'int')){
                    $data['msg_val'] = 1;
                }else if(false !== strpos($data_type,'time')){
                    $data['msg_val'] = Tools::get_now_date();
                }else if(false !== strpos($data_type,'date')){
                    $data['msg_val'] = date('Y-m-d');
                }else if(false !== strpos($data_type,'year')){
                    $data['msg_val'] = date('Y');
                }else{
                    //注释
                    $data['msg_val'] = Tools::get_comment_By_Field($tablename,$field);
                }

                $field_arr[] = $data;
            }
        }

        $this->assign('condition_field_arr',$field_arr);

        $html = view()->getContent();

        return json(Tools::set_ok('ok',$html));
    }

    //通用请求第三方接口
    function testapicurl(){
        //dump(input());die;
        $data = input('post_data');

        $post_data = [];
        if($data){
            foreach ($data as $key=>$val){
                $post_data[$val['name']] = $val['value'];
            }
        }
        $api_url = input('api_url');


        $res = Curl::curl_post($api_url, $post_data);
        return $res;
    }
}